//
//  LTEncryptionDataTool.swift
//  myMoya
//
//  Created by xiaoyi on 2020/4/26.
//  Copyright © 2020 lete. All rights reserved.
//

/**
 
 首先要有一个.h文件，这里使用Bridging-Header.h然后设置项目的Build Settings－－Swift Compiler－－Objective-C Bridging Header内容为DemoApp/Bridging-Header.h，这个与Bridging-Header.h位置有关，从项目的根目录开始在Objective-C Bridging Header选项里面写入Bridging-Header.h相对路径。

 需在桥接文件导入头文件 ，因为C语言的库
 #import <CommonCrypto/CommonDigest.h>
 #import <CommonCrypto/CommonCrypto.h>
 #import <CommonCrypto/CommonHMAC.h>
 
 字符串常用加密：MD5，sha1，base64
 使用：
 
 let str = "welcome to hangge.com"
 let key = "67FG"
 //  HMAC
 let hmacStr = str.hmac(algorithm: .SHA1, key: key)
 print("原始字符串：\(str)")
 print("key：\(key)")
 print("HMAC运算结果：\(hmacStr)")
 //  SHA224
 let SHA224 = str.hmac(algorithm: .SHA224, key: key)
 print("原始字符串：\(str)")
 print("key：\(key)")
 print("SHA224运算结果：\(SHA224)")
 //  md5
 let str1 = "欢迎来到zhuhai"
 let key2 = "你好"
 let md5 = str1.hmac(algorithm: .MD5, key: key2)
 print("原始字符串：\(str1)")
 print("key：\(key2)")
 print("md5运算结果：\(md5)")
 //  普通md5
 let md55 = str1.md5
 print("md55 = \(md55)")
 //  普通md5测试
 print("md测试 = \("lacar我是牛人才怪lacar".md5)")
 print("md用户测试 = \("用户名".md5)")
 print("md我们测试 = \("我们".md5)")
 print("md123测试 = \("123".md5)")
 print("mdming测试 = \("ming".md5)")
 print("md你好测试 = \("你好".md5)")
 print("mdlacar测试 = \("lacar".md5)")
 
 base64的使用：
 let base64Str = "让天方夜谭天"
 let encodeStr = base64Str.encodeToBase64()
 let decodeStr = encodeStr.decodeBase64()
 
 */
 
import UIKit
import Foundation


 
enum CryptoAlgorithm {
    case MD5, SHA1, SHA224, SHA256, SHA384, SHA512
    
    var HMACAlgorithm: CCHmacAlgorithm {
        var result: Int = 0
        switch self {
        case .MD5:      result = kCCHmacAlgMD5
        case .SHA1:     result = kCCHmacAlgSHA1
        case .SHA224:   result = kCCHmacAlgSHA224
        case .SHA256:   result = kCCHmacAlgSHA256
        case .SHA384:   result = kCCHmacAlgSHA384
        case .SHA512:   result = kCCHmacAlgSHA512
        }
        return CCHmacAlgorithm(result)
    }
    var digestLength: Int {
        var result: Int32 = 0
        switch self {
        case .MD5:      result = CC_MD5_DIGEST_LENGTH
        case .SHA1:     result = CC_SHA1_DIGEST_LENGTH
        case .SHA224:   result = CC_SHA224_DIGEST_LENGTH
        case .SHA256:   result = CC_SHA256_DIGEST_LENGTH
        case .SHA384:   result = CC_SHA384_DIGEST_LENGTH
        case .SHA512:   result = CC_SHA512_DIGEST_LENGTH
        }
        return Int(result)
    }
}
 
class LYBJiamiExtention: NSObject {
    
}
extension String  {
    
    var md5: String! {
        let str = self.cString(using: String.Encoding.utf8)
        let strLen = CC_LONG(self.lengthOfBytes(using: String.Encoding.utf8))
        let digestLen = Int(CC_MD5_DIGEST_LENGTH)
        let result = UnsafeMutablePointer<CUnsignedChar>.allocate(capacity: digestLen)
        CC_MD5(str!, strLen, result)
        return stringFromBytes(bytes: result, length: digestLen)
    }
    
    var sha1: String! {
        let str = self.cString(using: String.Encoding.utf8)
        let strLen = CC_LONG(self.lengthOfBytes(using: String.Encoding.utf8))
        let digestLen = Int(CC_SHA1_DIGEST_LENGTH)
        let result = UnsafeMutablePointer<CUnsignedChar>.allocate(capacity: digestLen)
        CC_SHA1(str!, strLen, result)
        return stringFromBytes(bytes: result, length: digestLen)
    }
    
    var sha256String: String! {
        let str = self.cString(using: String.Encoding.utf8)
        let strLen = CC_LONG(self.lengthOfBytes(using: String.Encoding.utf8))
        let digestLen = Int(CC_SHA256_DIGEST_LENGTH)
        let result = UnsafeMutablePointer<CUnsignedChar>.allocate(capacity: digestLen)
        CC_SHA256(str!, strLen, result)
        return stringFromBytes(bytes: result, length: digestLen)
    }
    
    var sha512String: String! {
        let str = self.cString(using: String.Encoding.utf8)
        let strLen = CC_LONG(self.lengthOfBytes(using: String.Encoding.utf8))
        let digestLen = Int(CC_SHA512_DIGEST_LENGTH)
        let result = UnsafeMutablePointer<CUnsignedChar>.allocate(capacity: digestLen)
        CC_SHA512(str!, strLen, result)
        return stringFromBytes(bytes: result, length: digestLen)
    }
    
    func stringFromBytes(bytes: UnsafeMutablePointer<CUnsignedChar>, length: Int) -> String{
        let hash = NSMutableString()
        for i in 0..<length {
            hash.appendFormat("%02x", bytes[i])
        }
        bytes.deallocate()
        return String(format: hash as String)
    }
    
    /**复杂的加密
     parama1:上面的枚举值 MD5, SHA1, SHA224, SHA256, SHA384, SHA512
     parama2: 加密的字符串
 
 */
    func hmac(algorithm: CryptoAlgorithm, key: String) -> String {
        let str = self.cString(using: String.Encoding.utf8)
        let strLen = Int(self.lengthOfBytes(using: String.Encoding.utf8))
        let digestLen = algorithm.digestLength
        let result = UnsafeMutablePointer<CUnsignedChar>.allocate(capacity: digestLen)
        let keyStr = key.cString(using: String.Encoding.utf8)
        let keyLen = Int(key.lengthOfBytes(using: String.Encoding.utf8))
        CCHmac(algorithm.HMACAlgorithm, keyStr!, keyLen, str!, strLen, result)
        let digest = stringFromResult(result: result, length: digestLen)
        result.deallocate()
        return digest
    }
    
    private func stringFromResult(result: UnsafeMutablePointer<CUnsignedChar>, length: Int) -> String {
        let hash = NSMutableString()
        for i in 0..<length {
            hash.appendFormat("%02x", result[i])
        }
        return String(hash)
    }
    
    
    /**
     *   Base64 加密
     *   return 加密字符串
     */
    func encodeToBase64() -> String {
        guard let data = self.data(using: String.Encoding.utf8) else { print("加密失败"); return "" }
        return data.base64EncodedString(options: Data.Base64EncodingOptions(rawValue: 0)) //系统提供的方法，iOS7之后可用
    }
    /**
     *   Base64 解密
     *   return 解密字符串
     */
    func decodeBase64() -> String {
        guard let data = Data(base64Encoded: self, options: Data.Base64DecodingOptions(rawValue: 0)) else { print("解密失败"); return ""                  }
        return String(data: data, encoding: String.Encoding.utf8)!
    }
    
   
}
